﻿using Infrastructure.DDD;
using Infrastructure.Extension;
using Infrastructure.Utils;
using Infrastructure.WebApi;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System.Net;

namespace Application.Service
{
    public class ManagerService : IManagerService
    {
        private TokenBuilder _tokenBuilder { get; set; }
        private JobManagerDbContext _context { get; set; }
        private readonly TokenOptions _tokenSetting;
        private readonly Accessor _accessor;
        private readonly List<SysRole> _roles;
        public ManagerService(JobManagerDbContext DbContext, IOptions<TokenOptions> tokenSetting, TokenBuilder tokenBuilder, IOptions<List<SysRole>> roles, Accessor accessor)
        {
            _context = DbContext;
            _tokenSetting = tokenSetting.Value;
            _tokenBuilder = tokenBuilder;
            _roles = roles.Value;
            _accessor = accessor;
        }


        #region 登录
        public async Task<UserLoginResponse> Login(UserLoginRequest request, string realIp)
        {
            var one = await _context.SysManager.FirstOrDefaultAsync(s => s.LoginCode == request.LoginCode);
            if (one == null) BusinessException.Throw("未找到该用户");
            if (!Password.Verify(request.Password, one.Password)) BusinessException.Throw("账号或密码错误");
            var dic = new Dictionary<string, object>();
            var managerUserInfo = new UserInfo
            {
                UserName = one.UserName,
                Id = one.Id,
                RoleKey = one.RoleKey,
                LoginCode = one.LoginCode
            };
            dic.Add("id", managerUserInfo.Id);
            dic.Add("name", managerUserInfo.UserName);
            dic.Add("roleId", managerUserInfo.RoleKey);
            dic.Add("refresh_token_limit_minute", _tokenSetting.refresh_token_limit_minute);//可以使其他服务免配置refresh_token_limit_minute
            #region log
            var operationLog = new SysLogOperation
            {
                Ip = realIp,
                Title = "登录系统",
                Api = "manager/login",
                OperatorId = one.Id,
                OperatorName = one.UserName,
                Note = $"logincode:{one.LoginCode}"
            };
            //_cap.Publish("operationLog.write", operationLog);
            #endregion
            return new UserLoginResponse
            {
                User = managerUserInfo,
                access_token = _tokenBuilder.CreateToken(dic, _tokenSetting.access_token_minute),
                refresh_token = _tokenBuilder.CreateToken(new Dictionary<string, object> { { "token_type", "refresh_token" } }, _tokenSetting.refresh_token_minute)
            };
        }

        /// <summary>
        /// 刷新token
        /// </summary>
        public Task<RefreshTokenResponse> RefreshToken(RefreshTokenRequest request, string access_token)
        {
            if (!access_token.Has()) BusinessException.Throw("缺失token");
            var tokenExpSeccond = _tokenBuilder.ExpSeccond(access_token);
            if (tokenExpSeccond == null) BusinessException.Throw("非法请求");
            if (tokenExpSeccond > _tokenSetting.refresh_token_limit_minute * 60) BusinessException.Throw(HttpStatusCode.Unauthorized, "长时间未操作，请重新登录");
            if (!_tokenBuilder.Verify(request.RefreshToken)) BusinessException.Throw(HttpStatusCode.Unauthorized, "太久没有登录了");//RefreshToken已失效

            var dic = TokenBuilder.GetPayLoad(access_token);
            return Task.FromResult(new RefreshTokenResponse
            {
                AccessToken = _tokenBuilder.CreateToken(dic, _tokenSetting.refresh_token_limit_minute)
            });
        }
        #endregion

        #region 获取列表
        public async Task<Page<UserInfo>> Get(UserRequest request)
        {
            var data = await _context.SysManager.AsQueryable()
                .WhereIf(request.Keyword.Has(), s => s.UserName.Contains(request.Keyword) || s.LoginCode.Contains(request.Keyword))
                .PageAsync(request.PageIndex, request.PageSize);

            return new Page<UserInfo>
            {
                List = data.List.Select(s => new UserInfo
                {
                    Id = s.Id,
                    UserName = s.UserName,
                    LoginCode = s.LoginCode,
                    RoleKey = s.RoleKey,
                }).ToList(),
                TotalCount = data.TotalCount
            };
        }
        #endregion

        #region CUD
        public async Task Add(CreateManagerRequest request)
        {
            request.StringTrim();
            if (await _context.SysManager.AnyAsync(s => s.LoginCode == request.LoginCode)) BusinessException.Throw($"已存在{request.LoginCode}！");
            var model = new SysManager
            {
                LoginCode = request.LoginCode,
                UserName = request.UserName,
                Password = Password.Create(request.Password),
                RoleKey = request.RoleKey
            };
            await _context.SysManager.AddAsync(model);
            await _context.SaveChangesAsync();
        }
        public async Task Update(UserEditRequest request)
        {
            var one = await _context.SysManager.FirstOrDefaultAsync(s => s.Id == request.Id);
            one.CheckNull();
            if (one.RoleKey == GlobalData.Role.SupperAdminRoleKey && one.RoleKey != request.RoleKey) BusinessException.Throw("不能更改超级管理员角色");
            one.UserName = request.UserName;
            one.RoleKey = request.RoleKey;
            await _context.SaveChangesAsync();
        }
        public async Task Delete(IdRequest request)
        {
            var one = await _context.SysManager.FirstOrDefaultAsync(s => s.Id == request.Id);
            one.CheckNull();
            if (one.RoleKey == GlobalData.Role.SupperAdminRoleKey) BusinessException.Throw("超级管理员不能删除");
            one.SoftDelete();
            await _context.SaveChangesAsync();
        }
        public async Task UpdatePassword(KeyRequest request)
        {
            var one = await _context.SysManager.FirstOrDefaultAsync(s => s.Id == _accessor.ManagerId);
            one.CheckNull();
            one.Password = Password.Create(request.Key);
            await _context.SaveChangesAsync();
        }
        #endregion

        #region 角色
        public List<SysRole> GetRoles()
        {
            return _roles;
        }
        #endregion

    }

    public interface IManagerService
    {
        Task<UserLoginResponse> Login(UserLoginRequest request, string realIp);
        Task<RefreshTokenResponse> RefreshToken(RefreshTokenRequest request, string access_token);
        Task<Page<UserInfo>> Get(UserRequest request);
        Task Add(CreateManagerRequest request);
        Task Update(UserEditRequest request);
        Task Delete(IdRequest request);
        Task UpdatePassword(KeyRequest request);
        List<SysRole> GetRoles();
    }
}
